//
//  NMURLSession.swift
//  NetEaseMusic
//
//  Created by SAGESSE on 2019/11/22.
//  Copyright © 2019 SAGESSE. All rights reserved.
//

import UIKit
import CommonCrypto
import SystemConfiguration
import SystemConfiguration.CaptiveNetwork

///
/// The NetEase Music Network Interface.
///
public class NMNetwork {
    
    
    static let shared: NMNetwork = .init()

    
    /// Network base URL.
    public var baseURL = "nm://interface3.music.163.com"
    
    

//    /// Network response callback.
//    public typealias CompleteHandler<T: Decodable> = ((Response<T>) -> Void)
//
//    /// Network response result.
//    public enum Result: Decodable, Equatable, CustomStringConvertible {
//
//        case success
//        case failure(Error)
//
//        /// Get error on failure
//        public var error: Error? {
//            switch self {
//            case .failure(let error):
//                return error
//
//            default:
//                return nil
//            }
//        }
//
//        public var description: String {
//            switch self {
//            case .failure(let error):
//                return "failure: \(error.localizedDescription)"
//
//            default:
//                return "success"
//            }
//        }
//
//        /// Implement decoding method.
//        public init(from decoder: Decoder) throws {
//            // Only prase object for specified keys.
//            let container = try decoder.container(keyedBy: CodingKeys.self)
//
//            // Prase raw value from decoder.
//            let code = try container.decodeIfPresent(Int.self, forKey: .code) ?? -1
//            let message = try container.decodeIfPresent(String.self, forKey: .message)
//
//            // In zero, is no error.
//            guard code != 0 else {
//                self = .success
//                return
//            }
//
//            // Making a errror.
//            self = .failure(Result.error(code, text: message))
//        }
//
//        /// Implement equal method.
//        public static func == (lhs: Result, rhs: Result) -> Bool {
//            switch (lhs, rhs) {
//            case (.success, .success),
//                 (.failure, .failure):
//                return true
//
//            default:
//                return false
//            }
//        }
//
//        public static let transparent = NSError(domain: "Network-Internal", code: -2, userInfo: [NSLocalizedDescriptionKey: ""]) as Error
//        public static func error(_ code: Int, text: String? = nil) -> Error {
//            var des = NSLocalizedString("\(code)", bundle: Bundle.main, comment: "")
//            if let text = text, des == "\(code)" {
//                des = text
//            }
//            return NSError(domain: "Network", code: code, userInfo: [
//                NSLocalizedDescriptionKey: des
//            ])
//        }
//
//        /// Making Mapping.
//        private enum CodingKeys: String, CodingKey {
//            case message = "responseMsg"
//            case code = "responseCode"
//        }
//    }
//
//    /// Network empty response object.
//    public final class Empty: Decodable {
//    }
//
//    /// Network response object.
//    public final class Response<T: Decodable>: Decodable {
//
//        /// Framework data.
//        public let result: Result
//
//        /// Custom data.
//        public let data: T?
//
//        /// Get error on failure
//        public var error: Error? {
//            return result.error
//        }
//
//        /// Making a failure response object.
//        public init(_ result: Result, data: T? = nil) {
//            self.data = data
//            self.result = result
//        }
//
//        /// Implement decoding method.
//        public required init(from decoder: Decoder) throws {
//            // Only prase object for specified keys.
//            let container = try decoder.container(keyedBy: CodingKeys.self)
//
//            // Prase framework data from decoder.
//            result = try container.decode(Result.self, forKey: .head)
//
//            // Parse user data from decoder.
//            data = try container.decodeIfPresent(T.self, forKey: .data)
//        }
//
//        /// Quickly create a failure response.
//        public static func failure(_ error: Error) -> Response {
//            return .init(.failure(error))
//        }
//
//        /// Quickly create a failure response with message.
//        public static func failure(_ code: Int = 0, text: String? = nil) -> Response {
//            return failure(Result.error(code, text: text))
//        }
//
//        /// Making Mapping.
//        private enum CodingKeys: String, CodingKey {
//            case data = "body"
//            case head = "head"
//        }
//    }
//
//
//    /// Network request rethod.
//    public enum Method: String {
//
//        case get
//        case post
//        case put
//        case delete
//
//        var encoding: Encoding {
//            switch self {
//            case .post,
//                 .put:
//                return .json
//
//            default:
//                return .urlencoded
//            }
//        }
//    }
//
//    /// Network request encoding.
//    public enum Encoding: String {
//        case json
//        case urlencoded
//    }
    
        
    /// The network state.
    public enum State {
        
        public static var isWWAN: Bool {
            return isReachable && flags?.contains(.isWWAN) ?? false
        }
        public static var isWifi: Bool {
            return !isWWAN
        }
        
        public static var isReachable: Bool {
            // Monitoring is not ready.
            guard let flags = self.flags else {
                return false
            }
            
            // The specified node name or address can be reached using the current network configuration.
            guard flags.contains(.reachable) else {
                return false
            }
            
            // The specified node name or address can be reached using the current network configuration, but a connection must first be established.
            guard flags.contains(.connectionRequired) else {
                return true
            }
            
            // The user must manually make the connection.
            guard !flags.contains(.interventionRequired) else {
                return false
            }
            
            // Check automatic connections are supported.
            guard flags.contains(.connectionOnDemand) || flags.contains(.connectionOnTraffic) else {
                return false
            }
            
            return true
        }
        
        /// Get current wifi ssid.
        /// WARN: In iOS 12, need to add the entitlements to access.
        public static var SSID: String? {
            // Get this device all interfaces.
            guard let interfaces = CNCopySupportedInterfaces() as NSArray? else {
                return nil
            }
            
            // The first interface is wifi.
            guard let interface = interfaces.firstObject else {
                return nil
            }
            
            // Get network info for specified interface.
            guard let attributes = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? else {
                return nil
            }
            
            return attributes[kCNNetworkInfoKeySSID] as? String
        }

        
        public static func busy() {
            DispatchQueue.main.async {
                counter += 1
                guard counter == 1 else {
                    return
                }
                UIApplication.shared.isNetworkActivityIndicatorVisible = true
            }
        }
        public static func idle() {
            DispatchQueue.main.async {
                counter = max(counter - 1, 0)
                guard counter == 0 else {
                    return
                }
                UIApplication.shared.isNetworkActivityIndicatorVisible = false
            }
        }
        
        /// Suspended all network requests.
        public static func suspend() {
            guard waiting == nil else {
                return
            }
            waiting = DispatchQueue(label: "Network-Waiting")
            semaphore = DispatchSemaphore(value: 0)
            waiting?.async { [semaphore] in
                // Lock the thread.
                semaphore?.wait()
            }
        }
        /// Resume all network requests.
        public static func resume() {
            guard waiting != nil else {
                return
            }
            waiting = nil
            semaphore?.signal()
            semaphore = nil
        }
        
        /// Start the network monitoring
        fileprivate static func startMonitoring() {
            // If it's already started, ignore it.
            guard self.reachability == nil else {
                return
            }
            
            var address = sockaddr_in()
            
            address.sin_len = .init(MemoryLayout.size(ofValue: address))
            address.sin_family = .init(AF_INET)
            
            self.reachability = withUnsafePointer(to: &address) {
                return $0.withMemoryRebound(to: sockaddr.self, capacity: 0) {
                    return SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
                }
            }
            
            // If reachability is nil, create is fail.
            guard let reachability = self.reachability else {
                return
            }
            
            // Create a network status updater.
            let SCNetworkReachabilityUpdater: @convention(c) (SCNetworkReachability, SCNetworkReachabilityFlags, UnsafeMutableRawPointer?) -> () = { (_, flags, _) in
                // Updating..
                State.flags = flags
            }
            
            // Setup callback and add schedule to runloop
            SCNetworkReachabilitySetCallback(reachability, SCNetworkReachabilityUpdater, nil)
            SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
            
            // Init.
            var flags = SCNetworkReachabilityFlags()
            SCNetworkReachabilityGetFlags(reachability, &flags)
            SCNetworkReachabilityUpdater(reachability, flags, nil)
        }
        /// Stop the network monitoring.
        fileprivate static func stopMonitoring() {
            // If there is no start, no need to stop.
            guard let reachability = self.reachability else {
                return
            }
            
            // Remove schedule for runloop.
            SCNetworkReachabilityUnscheduleFromRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
            
            // Release network reachability object.
            self.reachability = nil
        }

        
        fileprivate static var flags: SCNetworkReachabilityFlags?
        fileprivate static var reachability: SCNetworkReachability?
        fileprivate static var counter: Int = 0
        
        fileprivate static var waiting: DispatchQueue?
        fileprivate static var semaphore: DispatchSemaphore?
    }
    
    
//    /// Send a request(maybe suspend).
//      public func request<T>(_ url: String, _ parameters: [String: Any]? = nil, method: Method = .post, encoding: Encoding? = nil, complete: @escaping CompleteHandler<T>) {
//        // Need wait from queue?
//        guard let waiting = State.waiting else {
//            self.requestWithoutSuspend(url, parameters, method: method, encoding: encoding, complete: complete)
//            return
//        }
//
//        // Enter waiting status.
//        waiting.async {
//            // Exit waiting status.
//            DispatchQueue.main.async {
//                self.requestWithoutSuspend(url, parameters, method: method, encoding: encoding, complete: complete)
//            }
//        }
//    }
//
//    /// Send a request.
//    public func requestWithoutSuspend<T>(_ url: String, _ parameters: [String: Any]? = nil, method: Method = .post, encoding: Encoding? = nil, complete: @escaping CompleteHandler<T>) {
//        // Convert to URL.
//        guard let url = URL(string: url, relativeTo: URL(string: baseURL)) else {
//            return
//        }
//
//        // Generate request & parameters.
//        var request = URLRequest(url: url, timeoutInterval: 60)
//
//        request.httpMethod = method.rawValue.uppercased()
//
//
//        // Identifies and converts data of the specified content type.
//        switch encoding ?? method.encoding {
//        case .json:
//            // This is a json body.
//            request.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
//            request.httpBody = try? parameters.map {
//                return try JSONSerialization.data(withJSONObject: $0)
//            }
//
//        case .urlencoded:
//            // This is a urlencoded body.
//            request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
//            request.httpBody = parameters.flatMap {
//                var comp = URLComponents()
//                comp.queryItems = $0.map {
//                    return URLQueryItem(name: $0, value: "\($1)")
//                }
//                return comp.query?.data(using: .utf8)
//            }
//        }
//
//
//        request.addValue(encoding?.rawValue ?? method.encoding.rawValue, forHTTPHeaderField: "Content-Type")
//
////        //Cookie:
////        MUSIC_U=e358cc9187d186b8812771022ed903b18a0db3d6e169e5080df2edd908bf46158bfa3647090953cd3978aedb053b0b59384fe0dd1eca3a5f;
////        deviceId=e2174b3747ce2482e0e513e52484b643;
////        os=iPhone OS;
////        appver=7.0.0;
////        channel=distribution;
////        buildver=1466;
////        machineid=iPhone10.1;
////        osver=13.3.1
//
////
////        #if DEBUG
////        print("\(url.path) << \(try! String(data: JSONSerialization.data(withJSONObject: body), encoding: .utf8) ?? "")")
////        #endif
//
//        // Network start request.
//        State.busy()
//
//        // Send a request to server.
//        let task = URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
//            // Must be calleback in the main thread.
//            DispatchQueue.main.async {
//                // Network request completed.
//                State.idle()
//
////                #if DEBUG
////                print("\(url.path) >> \(data.map({ String(bytes: decrypt($0, forKey: url), encoding: .utf8) ?? "" }) ?? error as Any)")
////                #endif
////
//                // If data is nil, the request is failure.
//                guard let data = data, error == nil else {
//                    // Request failure for system error.
//                    complete(.failure(-1))
//                    return
//                }
//
////                // In request success case.
////                do {
////
////                    let decoder = JSONDecoderEx()
////                    let formatter = DateFormatter()
////                    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
////                    decoder.dateDecodingStrategy = .formatted(formatter)
////                    let response = try decoder.decode(Response<T>.self, from: decrypt(data, forKey: url))
////
////                    // Callback for request success.
////                    complete(response)
////
////                } catch (let error) {
////
////                    // Callback for request failure.
////                    complete(.failure(error))
////                }
//            }
//        }
//        task.resume()
//    }
//
    
    /// Network response object.
    public class Response: Decodable {
        
        /// Make a response from decoder.
        public required init(from decoder: Decoder) throws {
            self.decoder = decoder
            self.container = try decoder.container(keyedBy: JSONDecoderEx.CustomKey.self)
        }
        
        /// Decodes a value of the given type for the given key.
        public func decode<T>(_ type: T.Type, forKey key: String) throws -> T where T: Decodable {
            // Decodes a value of the given type for the given key.
            return try container.decode(type, forKey: .init(stringValue: key))
        }
        
        /// Decodes a value of the given type for the given key, if present.
        public func decodeIfPresent<T>(_ type: T.Type, forKey key: String) throws -> T? where T: Decodable {
            return try container.decodeIfPresent(type, forKey: .init(stringValue: key))
        }
        
        private var decoder: Decoder
        private var container: KeyedDecodingContainer<JSONDecoderEx.CustomKey>
    }

    
    /// Send a request.
    public func request(_ url: String, _ parameters: [String: Any]? = nil, complete: @escaping (Response?, Error?) -> ()) {
        // Convert to URL.
        guard let url = URL(string: url, relativeTo: URL(string: baseURL)) else {
            return
        }
        
        // Generate request & parameters.
        var request = URLRequest(url: url, timeoutInterval: 60)
        
        request.httpMethod = "POST"
        
        // Identifies and converts data of the specified content type.
        switch request.httpMethod {
        case "POST":
            // This is a json body.
            request.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
            request.httpBody = try? parameters.map {
                return try JSONSerialization.data(withJSONObject: $0)
            }
            
        default:
            // This is a urlencoded body.
            request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
            request.httpBody = parameters.flatMap {
                var comp = URLComponents()
                comp.queryItems = $0.map {
                    return URLQueryItem(name: $0, value: "\($1)")
                }
                return comp.query?.data(using: .utf8)
            }
        }
        
        // Send a request to server.
        let task = URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
            // If data is nil, the request is failure.
            guard let data = data, error == nil else {
                // Request failure for system error.
                complete(nil, error)
                return
            }
            
            // In request success case.
            do {
                let decoder = JSONDecoderEx()
                decoder.dateDecodingStrategy = .millisecondsSince1970
                let response = try decoder.decode(Response.self, from: data)
                
                // Callback for request success.
                complete(response, nil)
                
            } catch (let error) {
                // Callback for request failure.
                complete(nil, error)
            }
        }
        task.resume()
    }
    
    
    private init() {
        State.startMonitoring()
        
        let handle = { (task: URLSessionEx.Plugin.Task) in
            let url = task.url
            NMCache.shared.remoteURL(url) { [weak task] (url, error) in
                task.map {
                    // When the load error, force a redirect to an invalid address.
                    var request = $0.request
                    request.url = url ?? URL(string: "http://localhost:0")
                    $0.redirecting(to: request)
                }
            }
        }
        
        // Registered routing table.
        URLSessionEx.Route.shared.get("/url/video", handle: handle)
        URLSessionEx.Route.shared.get("/url/movie", handle: handle)
        URLSessionEx.Route.shared.get("/url/image", handle: handle)
        
        URLSessionEx.Plugin.register(URLSessionEx.Route.shared)
        URLSessionEx.Plugin.register(URLSessionEx.Security.shared)
    }

    
//    https://music.163.com/weapi/login

    func test() {
        Configuration.shared.udid = "e2174b3747ce2482e0e513e52484b643"
        Configuration.shared.token = "e358cc9187d186b8812771022ed903b182532af8fd1d7e39f032e0f5a9ffb838c7a20fda82f435bb8581a6603f72ae9bfe2897047e8106fb"
        Configuration.shared.sync()
    }
}


// MARK: -


extension NMNetwork {
    class Configuration {
        
        static let shared: Configuration = .init()
        
        var name: String // Fast
        var channel: String // distribution
        
        var build: String // 1446
        var version: String // 7.0.0
        
        var systemName: String // iOS
        var systemModel: String // iPhone
        var systemVersion: String // 13.4
        
        var udid: String? {
            willSet {
                if newValue != udid {
                    Self.setPermanentValue(newValue, forKey: Self.udidKey)
                }
            }
        }
        var token: String? {
            willSet {
                if newValue != token {
                    Self.setPermanentValue(newValue, forKey: Self.tokenKey)
                }
            }
        }
        
        var machine: String

        
        var agent: String {
            return "\(name) \(version)/\(build) (\(systemModel); \(systemName) \(systemVersion); \(Locale.current.identifier))"
        }
        var cookies: String {
            let cookies = [
                "MUSIC_U": token,
                "deviceId": udid,
                "os": "\(systemModel) OS",
                "appver": version,
                "channel": channel,
                "buildver": build,
                "machineid": machine,
                "osver": systemVersion,
            ]
            return cookies.reduce("") {
                guard let value = $1.value else {
                    return $0
                }
                let cookie = "\($1.key)=\(value)"
                if $0.isEmpty {
                    return cookie
                }
                return "\($0); \(cookie)"
            }
        }
        
        func sync() {
            guard let url = URL(string: "https://music.163.com") else {
                return
            }
            
            let cookies = [
                "MUSIC_U": token,
                "deviceId": udid,
                "os": "\(systemModel) OS",
                "appver": version,
                "channel": channel,
                "buildver": build,
                "machineid": machine,
                "osver": systemVersion,
            ]
            
            let expires = Calendar.current.date(byAdding: .year, value: 100, to: .init(), wrappingComponents: true)
            let x: [HTTPCookie] = cookies.compactMap {
                guard let value = $1 else {
                    return nil
                }
                return HTTPCookie(properties: [
                    .name: $0,
                    .value: $1,
                    .expires: expires,
                    .domain: ".music.163.com",
                    .path: "/",
                ])
            }
            
            HTTPCookieStorage.shared.setCookies(x, for: url, mainDocumentURL: url)
        }
        
        
        private init() {
            
            let device = UIDevice.current
            let info = Bundle.main.infoDictionary
            
            self.name = info?["CFBundleName"] as? String ?? ""
            self.channel = "distribution"
            
            self.build = info?["CFBundleVersion"] as? String ?? "1"
            self.version = info?["CFBundleShortVersionString"] as? String ?? "1.0"
            
            self.systemName = device.systemName
            self.systemModel = device.model
            self.systemVersion = device.systemVersion
            
            #if targetEnvironment(simulator)
            self.machine = "iPhone10.1"
            #else
            self.machine = {
                var sinfo = utsname()
                uname(&sinfo)
                return withUnsafePointer(to: sinfo.machine) {
                    return $0.withMemoryRebound(to: UInt8.self, capacity: 0) {
                        return String(cString: $0)
                    }
                }
            }()
            #endif
            
            self.udid = Self.permanentValue(forKey: Self.udidKey) ?? Self.generateUDID()
            self.token = Self.permanentValue(forKey: Self.tokenKey)
        }
        
        /// Permanent preservation of data.
        private static func setPermanentValue(_ value: String?, forKey key: String) {

            // Set value to user defautls.
            UserDefaults.standard.set(value ?? NSNull(), forKey: key)
            UserDefaults.standard.synchronize()

            // Configure the search setting.
            var setting = [
                // Configure the keychain key type.
                kSecClass: kSecClassGenericPassword as Any,

                kSecAttrService: "music.163.com" as Any,
                kSecAttrAccount: key as Any
            ]
            
            // Delete old item before add new item
            SecItemDelete(NSDictionary(dictionary: setting))
            guard let data = value?.data(using: .utf8) else {
                return
            }

            // Add item to keychain with the search dictionary
            setting[kSecValueData] = data
            SecItemAdd(NSDictionary(dictionary: setting), nil)
        }
        /// Read data for permanent preservationed.
        private static func permanentValue(forKey key: String) -> String? {

            // Read data from user defatuls.
            if let value = UserDefaults.standard.object(forKey: key) {
                return value as? String
            }

            // Configure the search setting.
            let setting = [
                // Configure the keychain key type.
                kSecClass: kSecClassGenericPassword as Any,

                kSecAttrService: "music.163.com" as Any,
                kSecAttrAccount: key as Any,

                // Gets result data of data.
                kSecReturnData: kCFBooleanTrue as Any
            ]
            
            // Start query the keychain query.
            var result: CFTypeRef?
            guard SecItemCopyMatching(NSDictionary(dictionary: setting), &result) == noErr, let data = result as? Data else {
                return nil
            }

            // Convert data to a string
            return String(bytes: data, encoding: .utf8).map {

                // Set value to user defautls, reduce Keychain access count.
                UserDefaults.standard.set($0, forKey: key)
                UserDefaults.standard.synchronize()

                return $0
            }
        }
        
        /// Generate a new UDID.
        private static func generateUDID() -> String {
            // Generate a UUID to replace the UDID.
            var udid = UUID().uuidString
            
            // Try to obtain idfa.
            if let cls = NSClassFromString("ASIdentifierManager") as AnyObject? {
                if cls.value(forKeyPath: "sharedManager.isAdvertisingTrackingEnabled") as? Bool ?? false {
                    udid = cls.value(forKeyPath: "sharedManager.advertisingIdentifier.uuidString") as? String ?? udid
                }
            }
            
            // Save to keychain to prevent updates.
            udid = udid.replacingOccurrences(of: "-", with: "").lowercased()
            setPermanentValue(udid, forKey: Self.udidKey)
            return udid
        }
        
        private static let udidKey: String = "udid.music.163.com"
        private static let tokenKey: String = "token.music.163.com"
    }
}


// MARK: -


public extension URLSessionEx {
    ///
    /// Network interception plug-in
    ///
    class Route: URLSessionEx.Plugin {
        
        static let shared: Route = .init()
        
        public override func supported(_ request: URLRequest) -> Bool {
            return handle(request) != nil
        }
        
        
        public override func start(_ task: URLSessionEx.Plugin.Task, interrupt: inout Bool) {
            handle(task.request).map {
                interrupt = true
                $0(task)
            }
        }
        
        func get(_ rule: String, handle: @escaping (URLSessionEx.Plugin.Task) -> ()) {
            set(rule, method: "GET", handle: handle)
        }
        func post(_ rule: String, handle: @escaping (URLSessionEx.Plugin.Task) -> ()) {
            set(rule, method: "POST", handle: handle)
        }

        func set(_ rule: String, method: String, handle: @escaping (URLSessionEx.Plugin.Task) -> ()) {

            var map = rules[method]
            if map == nil {
                map = NSMutableDictionary()
                rules[method] = map
            }
            
            map?[rule] = handle
        }
        
        func handle(_ request: URLRequest) -> ((URLSessionEx.Plugin.Task) -> ())? {
            guard let url = request.url, let method = request.httpMethod else {
                return nil
            }
            return rules[method.uppercased()]?[url.path] as? ((URLSessionEx.Plugin.Task) -> ())
            
        }
        
        var rules: [String: NSMutableDictionary] = [:]
    }
}


// MARK: -


public extension URLSessionEx {
    ///
    /// Network reinforcement plug-in.
    ///
    class Security: URLSessionEx.Plugin {

        public enum Algorithm {
            case eapi
            case unknown1
        }
        
        public static let shared: Security = .init()
        
        public override func supported(_ request: URLRequest) -> Bool {
            return request.url?.scheme == "nm"
        }
        
        public override func start(_ task: URLSessionEx.Plugin.Task, interrupt: inout Bool) {
            
            let configuration = NMNetwork.Configuration.shared
            guard let url = task.url else {
                return
            }
            
            var request = task.request
            
            // Generated new URL.
            if var newURL = URLComponents(url: url, resolvingAgainstBaseURL: true) {
                // Repair URL protcol.
                newURL.scheme = "https"
                
                // Parameters of are handled only if encryption is required.
                if task.request.httpMethod?.compare("POST") == .orderedSame {
                    // Repair URL path.
                    if let range = newURL.path.range(of: "/batch"), range.lowerBound == newURL.path.startIndex {
                        newURL.path.replaceSubrange(range, with: "/eapi/batch")
                    }
                    if let range = newURL.path.range(of: "/api"), range.lowerBound == newURL.path.startIndex {
                        newURL.path.replaceSubrange(range, with: "/eapi")
                    }
                    
                    // Repair URL query.
                    newURL.queryItems = newURL.queryItems ?? []
                    newURL.queryItems?.append(.init(name: "_nmclfl", value: "1"))
                }
                
                // Pepair request url.
                request.url = newURL.url
            }
            
            request.setValue(configuration.agent, forHTTPHeaderField: "User-Agent")
            HTTPCookieStorage.shared.cookies(for: url).map(HTTPCookie.requestHeaderFields)?.forEach {
                request.setValue($1, forHTTPHeaderField: $0)
            }

            // Non-post request, no encryption and decryption required.
            guard task.request.httpMethod?.compare("POST") == .orderedSame else {
                // Redirects directly to the specified request.
                task.redirecting(to: request)
                return
            }
            
            // Gets the JSON data the request body and header.
            let body: NSMutableDictionary = [
                "os": "iOS",
                "verifyId": 1,
                "e_r": true
            ]
            let header: NSMutableDictionary = [
                "os": "iPhone OS",
                "appver": configuration.version,
                "deviceInfo": "",
                "requestId": UUID().uuidString,
                "osver": configuration.systemVersion
            ]
            
            // Autofill.
            body["MUSIC_U"] = configuration.token
            header["MUSIC_U"] = configuration.token
            body["deviceId"] = configuration.udid
            header["deviceId"] = configuration.udid
            
            // Read the data in the original request.
            if let oldBody = try? JSONSerialization.jsonObject(with: request.httpBody ?? .init()) as? [String: Any] {
                // Merge the contents in the body.
                body.addEntries(from: oldBody)
                
                // Merge the contents in the header.
                if let oldHeader = oldBody["header"] as? [String: Any] {
                    header.addEntries(from: oldHeader)
                }
            }

            // Update to the latest header.
            body["header"] = header
            
            // Encrypt and generate urlencode-encoded data.
            request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
            request.httpBody = try? String(data: JSONSerialization.data(withJSONObject: body), encoding: .utf8).flatMap {

//                // Trace request/response data in debug mode.
//                #if DEBUG
//                self.logger.trace?.write("\(url.path) < \($0)")
//                #endif

                return Self.encrypt(url.path, json: $0).flatMap {
                    return "params=\($0))".data(using: .utf8)
                }
            }
            
            // Send a real request and decrypt the request result.
            let newTask = URLSession.shared.dataTask(with: request) { [weak task] data, response, error in
                // Check for errors.
                guard let data = data, let response = response else {
                    task?.fail(error ?? URLSessionEx.error(NSURLErrorBadServerResponse))
                    return
                }
                
                // Decrypt and forward.
                let body = Self.decrypt(data)?.data(using: .utf8) ?? data
                task?.receive(response, data: body, cacheStoragePolicy: .allowed)
                task?.finish()
                
                // Trace request/response data in debug mode.
//                #if DEBUG
//                print("\(String(data: body, encoding: .utf8) ?? "nobody")")
//                #endif
            }
            task.redirecting(to: newTask)
            interrupt = true // Is exclusive mode.
        }
        
        public static func encrypt(_ url: String, json: String, for algorithm: Algorithm = .eapi) -> String? {
            // Load all secret keys into memory.
            let util = keys.compactMap { decrypt($0) }
            guard let primary = decrypt(key(from: algorithm)), util.count == 4 else {
                return nil
            }
            
            // Generate the signature and request body .
            let signature = md5(util[1] + url + util[2] + json + util[3]).lowercased()
            let body = autoreleasepool { () -> NSMutableData in
                // Align the length and fill the padded length.
                let body = NSMutableData()
                let param = url + util[0] + json + util[0] + signature
                let length = param.lengthOfBytes(using: .utf8)
                let padding = 16 - (length % 16)
                
                // Resize and copy contents to buffer.
                body.length = length + padding
                memcpy(body.mutableBytes, param, length)
                memset(body.mutableBytes.advanced(by: length), .init(padding), padding)
                
                return body
            }
            
            // Use key to encrypt all contents in data.
            _ = stride(from: 0, to: body.count, by: 16).reduce(Key(string: primary)) {
                encrypt(into: body.mutableBytes.advanced(by: $1), for: $0)
                return $0
            }
            
            return hex(body.mutableBytes, count: body.count)
        }
        public static func decrypt(_ data: Data, for algorithm: Algorithm = .eapi) -> String? {
            // Load data and master key into memory.
            return decrypt(key(from: algorithm)).flatMap {
                return decrypt(data, forKey: Key(string: $0).reversed())
            }
        }
        
        
        public static func md5(_ text: String) -> String {
            var bytes = [UInt8](repeating: 0, count: .init(CC_MD5_DIGEST_LENGTH))
            CC_MD5(text, .init(text.lengthOfBytes(using: .utf8)), &bytes)
            return hex(&bytes, count: bytes.count)
        }
        
        public static func hex(_ ptr: UnsafeRawPointer, count: Int) -> String {
            let str = NSMutableString(capacity: count * 2 + 1)
            // Transform the data
            stride(from: 0, to: count, by: 1).forEach {
                let value = ptr.load(fromByteOffset: $0, as: UInt8.self)
                str.appendFormat("%02X", value)
            }
            return str as String
        }
        public static func hex(_ text: String) -> Data? {
            // Create output buffer.
            let length = text.lengthOfBytes(using: .utf8)
            guard let payload = NSMutableData(length: length / 2) else {
                return nil
            }
            
            // Binding pointer.
            let dest = payload.mutableBytes.bindMemory(to: UInt8.self, capacity: 0)
            let src = text.withCString { $0 }
            
            // Transform the data
            stride(from: 0, to: length, by: 2).forEach {
                dest[$0 / 2] = .init(digittoint(.init(src[$0 + 0])) << 4 | digittoint(.init(src[$0 + 1])))
            }
            
            return payload as Data
        }
        
        public static func prase(_ str: String) -> Data? {
            // Decode the data from key first.
            guard let data = NSMutableData(base64Encoded: str, options: .ignoreUnknownCharacters) else {
                return nil
            }
            
            let base = data.mutableBytes.bindMemory(to: UInt8.self, capacity: 0)
            for index in 0 ..< data.count {
                base[index] = ~base[index]
            }
            
            return data as Data
        }
        
        /// The image url signature.
        public static func signature(_ key: String) -> String? {
            // Generating bytes data.
            var result = key.data(using: .utf8)
            var security = "3go8&$8*3*3h0k(2)2".data(using: .utf8)

            // Encryption bytes data.
            return result?.withUnsafeMutableBytes { lhs in
                // Perform simpleKeyXOR:withBytes:len:
                security?.withUnsafeMutableBytes { rhs in
                    lhs.enumerated().forEach {
                        lhs[$0] = $1 ^ rhs.load(fromByteOffset: $0 % rhs.count, as: UInt8.self)
                    }
                }
                // Perform MD5 signature.
                let buffer =  UnsafeMutablePointer<UInt8>.allocate(capacity: .init(CC_MD5_DIGEST_LENGTH))
                CC_MD5(lhs.baseAddress, .init(lhs.count), buffer)
                
                // Perform Base64 encryption and formatting result.
                var str = Data(bytes: buffer, count: .init(CC_MD5_DIGEST_LENGTH)).base64EncodedString()
                str = str.replacingOccurrences(of: "/", with: "_")
                str = str.replacingOccurrences(of: "+", with: "-")
                return str
            }
        }

        private static func encrypt(into src: UnsafeMutableRawPointer, for key: Key) {
            
            let lhs = src.bindMemory(to: Block.self, capacity: 0)
            let rhs = key.bytes
            
            @inline(__always) func xor(_ a: Block, _ b: Block, _ c: Block, _ d: Block) -> Block {
                var x0 = Block.zero
                x0 ^= table[2][.init(a >> 24 & 0xff)]
                x0 ^= table[3][.init(b >> 16 & 0xff)]
                x0 ^= table[0][.init(c >> 8 & 0xff)]
                x0 ^= table[1][.init(d >> 0 & 0xff)]
                return x0
            }
            @inline(__always) func or(_ a: Block, _ b: Block, _ c: Block, _ d: Block) -> Block {
                var x0 = Block.zero
                x0 |= table[0][.init(a >> 24 & 0xff)] & 0xff000000
                x0 |= table[1][.init(b >> 16 & 0xff)] & 0x00ff0000
                x0 |= table[2][.init(c >> 8 & 0xff)]  & 0x0000ff00
                x0 |= table[3][.init(d >> 0 & 0xff)]  & 0x000000ff
                return x0
            }
            
            // [w16, w4, w6, w17] + [w12, w14, w17, w5]
            var part = stride(from: 0, to: 4, by: 1).map { lhs[$0].byteSwapped ^ rhs[$0] } + .init(repeating: 0, count: 4)
            
            _ = stride(from: key.length / 2, to: 0, by: -1).reduce(rhs.advanced(by: 4)) {
                
                part[4] = xor(part[0], part[1], part[2], part[3]) ^ $0[0] // 0x42d77fcf XREF w12
                part[5] = xor(part[1], part[2], part[3], part[0]) ^ $0[1] // 0x223c5aca XREF w14
                part[6] = xor(part[2], part[3], part[0], part[1]) ^ $0[2] // 0x72effa43 XREF w17
                part[7] = xor(part[3], part[0], part[1], part[2]) ^ $0[3] // 0xd79c87a3 XREF w5
                
                // The last line requires special process.
                guard $1 > 1 else {
                    // 24 a0 14 cf ac f8 5f fb e9 47 39 c5 a9 16 8b 2e
                    lhs[0] = (or(part[4], part[5], part[6], part[7]) ^ $0[4]).byteSwapped
                    lhs[1] = (or(part[5], part[6], part[7], part[4]) ^ $0[5]).byteSwapped
                    lhs[2] = (or(part[6], part[7], part[4], part[5]) ^ $0[6]).byteSwapped
                    lhs[3] = (or(part[7], part[4], part[5], part[6]) ^ $0[7]).byteSwapped
                    return $0
                }
                
                part[0] = xor(part[4], part[5], part[6], part[7]) ^ $0[4] // 0x5c71ef49 XREF w16
                part[1] = xor(part[5], part[6], part[7], part[4]) ^ $0[5] // 0x9daad0c8 XREF w4
                part[2] = xor(part[6], part[7], part[4], part[5]) ^ $0[6] // 0x6277b8a8 XREF w6
                part[3] = xor(part[7], part[4], part[5], part[6]) ^ $0[7] // 0x859b100f XREF w17
                
                return $0.advanced(by: 8)
            }
        }
        private static func decrypt(into src: UnsafeMutableRawPointer, for key: Key) {
            
            let lhs = src.bindMemory(to: Block.self, capacity: 0)
            let rhs = key.bytes
            
            @inline(__always) func xor(_ a: Block, _ b: Block, _ c: Block, _ d: Block) -> Block {
                var x0 = Block.zero
                x0 ^= table[4][.init(a >> 24 & 0xff) + 10]
                x0 ^= table[5][.init(b >> 16 & 0xff) + 10]
                x0 ^= table[6][.init(c >> 8 & 0xff) + 10]
                x0 ^= table[7][.init(d >> 0 & 0xff) + 10]
                return x0
            }
            @inline(__always) func or(_ a: Block, _ b: Block, _ c: Block, _ d: Block) -> Block {
                return table[8].advanced(by: 10).withMemoryRebound(to: UInt8.self, capacity: 0) {
                    var x0 = Block.zero
                    x0 |= .init($0[.init(a >> 24 & 0xff)]) << 24
                    x0 |= .init($0[.init(b >> 16 & 0xff)]) << 16
                    x0 |= .init($0[.init(c >> 8 & 0xff)]) << 8
                    x0 |= .init($0[.init(d >> 0 & 0xff)]) << 0
                    return x0
                }
            }
            
            // [w11, w15, w6, w4] + [w8, w10, w4, w5]
            var part = stride(from: 0, to: 4, by: 1).map { lhs[$0].byteSwapped ^ rhs[$0] } + .init(repeating: 0, count: 4)
            
            // 2d 33 36 63 64 34 37 39 62 36 62 35 2d 03 03 03
            _ = stride(from: key.length / 2, to: 0, by: -1).reduce(rhs.advanced(by: 4)) {
                
                part[4] = xor(part[0], part[3], part[2], part[1]) ^ $0[0] // 0xb9f48fee XREF w8
                part[5] = xor(part[1], part[0], part[3], part[2]) ^ $0[1] // 0x5727e28b XREF w10
                part[6] = xor(part[2], part[1], part[0], part[3]) ^ $0[2] // 0x9069f20e XREF w4
                part[7] = xor(part[3], part[2], part[1], part[0]) ^ $0[3] // 0xec01321b XREF w5
                
                // The last line requires special process.
                guard $1 > 1 else {
                    lhs[0] = (or(part[4], part[7], part[6], part[5]) ^ $0[4]).byteSwapped
                    lhs[1] = (or(part[5], part[4], part[7], part[6]) ^ $0[5]).byteSwapped
                    lhs[2] = (or(part[6], part[5], part[4], part[7]) ^ $0[6]).byteSwapped
                    lhs[3] = (or(part[7], part[6], part[5], part[4]) ^ $0[7]).byteSwapped
                    return $0
                }
                
                part[0] = xor(part[4], part[7], part[6], part[5]) ^ $0[4] // 0xa0daf64b XREF w11
                part[1] = xor(part[5], part[4], part[7], part[6]) ^ $0[5] // 0x13f526c0 XREF w15
                part[2] = xor(part[6], part[5], part[4], part[7]) ^ $0[6] // 0x580538f2 XREF w6
                part[3] = xor(part[7], part[6], part[5], part[4]) ^ $0[7] // 0x12bd3ae2 XREF w4
                
                return $0.advanced(by: 8)
            }
        }
        
        private static func decrypt(_ data: Data, forKey key: Key) -> String? {
            // Parse the key to `Key` object.
            let body = (data as? NSMutableData) ?? NSMutableData(data: data)
            guard !body.isEmpty else {
                return nil
            }
            
            // Use key to encrypt all contents in data.
            stride(from: 0, to: body.count, by: 16).forEach {
                decrypt(into: body.mutableBytes.advanced(by: $0), for: key)
            }
            
            // Remove invalid data.
            let padding = body.mutableBytes.load(fromByteOffset: data.count - 1, as: UInt8.self)
            guard padding <= body.length else {
                return nil // Is a error.
            }
            body.length -= .init(padding)
            
            // Transform the data
            return String(data: body as Data, encoding: .utf8)
        }
        private static func decrypt(_ key: String) -> String? {
            // Load data and master key into memory.
            return prase(key).flatMap { data in
                return Key(base64Encoded: "oKCZkIGIvfDh0L2okfjdwA==").flatMap { key in
                    return decrypt(data as Data, forKey: key.reversed())
                }
            }
        }
        
        // Convert the algorithm into a security key.
        private static func key(from algorithm: Algorithm) -> String {
            switch algorithm {
            case .eapi:
                return "NK0yDVMhyMOspoFiqhNTeQ1Zo2uvugbmNCnEhEglXFc="
                
            case .unknown1:
                return "b4o8Aolq9SB6pwNL7mfWnw1Zo2uvugbmNCnEhEglXFc="
            }
        }
        
        
        /// Key required for decrypt of encrypt.
        private class Key {
            
            var bytes: UnsafeMutablePointer<Block>
            var length: Int
            
            // Create a empty key.
            private init() {
                bytes = .allocate(capacity: 64)
                length = 10
            }
            
            convenience init<T>(bytes: UnsafePointer<T>) {
                self.init()
                bytes.withMemoryRebound(to: Block.self, capacity: 0) {
                    load($0, bits: 128)
                }
            }
            
            convenience init(string: String) {
                self.init(bytes: string.withCString { $0 })
            }
            
            convenience init?(base64Encoded: String) {
                // Decode base64 to data.
                guard let data = prase(base64Encoded) as NSData? else {
                    return nil
                }
                
                // Load the key from the string of base64 string.
                self.init()
                self.load(data.bytes.bindMemory(to: Block.self, capacity: 0), bits: 128)
            }
            deinit {
                bytes.deallocate()
            }
            
            func load(_ src: UnsafePointer<Block>, bits: Int) {
                // 5f 5f 66 6f 7e 77 42 0f 1e 2f 42 57 6e 07 22 3f
                // 6f 66 5f 5f 0f 42 77 7e 57 42 2f 1e 3f 22 07 6e
                stride(from: 0, to: bits / 8, by: 1).forEach {
                    bytes[$0] = src[$0].byteSwapped
                }
                
                // 6f 66 5f 5f 0f 42 77 7e 57 42 2f 1e 3f 22 07 6e
                // f0 13 cc 9b ff 51 bb e5 a8 13 94 fb 97 31 93 95
                // da 9b 0b 45 25 ca b0 a0 8d d9 24 5b 1a e8 b7 ce
                // 51 39 90 e8 74 f3 20 48 f9 2a 04 13 e3 c2 b3 dd
                // 90 28 b5 8d e4 db 95 c5 1d f1 91 d6 fe 33 22 0b
                // bb 93 76 0e 5f 48 e3 cb 42 b9 72 1d bc 8a 50 16
                // fc f6 08 7d a3 be eb b6 e1 07 99 ab 5d 8d c9 bd
                // 86 ba 55 e0 25 04 be 56 c4 03 27 fd 99 8e ee 40
                // 8f 54 4c 48 aa 50 f2 1e 6e 53 d5 e3 f7 dd 3b a3
                // 85 3c 8d b1 2f 6c 7f af 41 3f aa 4c b6 e2 91 ef
                // 5a 72 15 06 75 1e 6a a9 34 21 c0 e5 82 c3 51 0a
                _ = stride(from: 0, to: 10, by: 1).reduce(bytes) {
                    let x0 = $0[3]
                    var x1 = $0[0]
                    
                    x1 ^= table[0][.init(x0 >> 16 & 0xff)] & 0xff000000   // 0x9a5f666f SEG 0x103dbbde0
                    x1 ^= table[1][.init(x0 >> 8 & 0xff)] & 0x00ff0000    // 0x9acc666f SEG 0x103dbc1e0
                    x1 ^= table[2][.init(x0 >> 0 & 0xff)] & 0x0000ff00    // 0x9acc136f SEG 0x103dbc5e0
                    x1 ^= table[3][.init(x0 >> 24 & 0xff)] & 0x000000ff   // 0x9acc13f0 SEG 0x103dbc9e0
                    x1 ^= table[4][.init($1)]                             // 0x9bcc13f0 SEG 0x103dbcde0
                    
                    $0[4] = x1
                    $0[5] = $0[4] ^ $0[1]                               // 0xe5bb51ff
                    $0[6] = $0[5] ^ $0[2]                               // 0xfb9413a8
                    $0[7] = $0[6] ^ $0[3]                               // 0x95933197
                    
                    return $0.advanced(by: 4)
                }
                
                // Update ciphertext length information.
                length = 10
            }
            func reversed() -> Self {
                // 5a 72 15 06 75 1e 6a a9 34 21 c0 e5 82 c3 51 0a
                // 85 3c 8d b1 2f 6c 7f af 41 3f aa 4c b6 e2 91 ef
                // 8f 54 4c 48 aa 50 f2 1e 6e 53 d5 e3 f7 dd 3b a3
                // 86 ba 55 e0 25 04 be 56 c4 03 27 fd 99 8e ee 40
                // fc f6 08 7d a3 be eb b6 e1 07 99 ab 5d 8d c9 bd
                // bb 93 76 0e 5f 48 e3 cb 42 b9 72 1d bc 8a 50 16
                // 90 28 b5 8d e4 db 95 c5 1d f1 91 d6 fe 33 22 0b
                // 51 39 90 e8 74 f3 20 48 f9 2a 04 13 e3 c2 b3 dd
                // da 9b 0b 45 25 ca b0 a0 8d d9 24 5b 1a e8 b7 ce
                // f0 13 cc 9b ff 51 bb e5 a8 13 94 fb 97 31 93 95
                // 6f 66 5f 5f 0f 42 77 7e 57 42 2f 1e 3f 22 07 6e
                stride(from: 0, to: length / 2, by: 1).forEach {
                    
                    let x0 = bytes.advanced(by: 4 * $0).withMemoryRebound(to: UInt64.self, capacity: 2) { $0 }
                    let x1 = bytes.advanced(by: 4 * (length - $0)).withMemoryRebound(to: UInt64.self, capacity: 2) { $0 } // bease `0` is input src, so `count - 0` is last item.
                    
                    swap(&x0[0], &x1[0])
                    swap(&x0[1], &x1[1])
                }
                
                // 5a 72 15 06 75 1e 6a a9 34 21 c0 e5 82 c3 51 0a
                // 0c 96 15 0a 08 ac 65 52 ee 20 2e 78 f9 1f 8a 46
                // 46 f4 20 4d 04 3a 70 58 e6 8c 4b 2a 17 3f a4 3e
                // 86 1c 5c 4f 42 ce 50 15 e2 b6 3b 72 f1 b3 ef 14
                // b2 52 b8 27 c4 d2 0c 5a a0 78 6b 67 13 05 d4 66
                // 35 67 58 5a 76 80 b4 7d 64 aa 67 3d b3 7d bf 01
                // d2 0d ec b3 43 e7 ec 27 12 2a d3 40 d7 d7 d8 3c
                // 81 10 60 e1 91 ea 00 94 51 cd 3f 67 c5 fd 0b 7c
                // e1 3b 2e fb 10 fa 60 75 c0 27 3f f3 94 30 34 1b
                // b5 bb fa 40 f1 c1 4e 8e d0 dd 5f 86 54 17 0b e8
                // 6f 66 5f 5f 0f 42 77 7e 57 42 2f 1e 3f 22 07 6e
                _ = stride(from: 1, to: length, by: 1).reduce(bytes.advanced(by: 4)) { base, _ in
                    _ = stride(from: 0, to: 4, by: 1).forEach {
                        let x0 = base[$0]
                        var x1 = Block.zero
                        
                        x1 ^= table[4][.init(table[3][.init(x0 >> 24 & 0xff)] & 0xff) + 10]   // 0x744ebc37
                        x1 ^= table[5][.init(table[3][.init(x0 >> 16 & 0xff)] & 0xff) + 10]   // 0xfc4935bc
                        x1 ^= table[6][.init(table[3][.init(x0 >> 8 & 0xff)] & 0xff) + 10]    // 0xcbf6467b
                        x1 ^= table[7][.init(table[3][.init(x0 >> 0 & 0xff)] & 0xff) + 10]    // 0x0a15960c
                        
                        base[$0] = x1
                    }
                    return base.advanced(by: 4)
                }
                
                return self
            }
        }
        
        /// Predefined processing size.
        private typealias Block = UInt32
        
        
        /// Magic data from 0x103dbbde0.
        private static let keys: [String] = [
            "V5p8eyp8u5QeHJK5mqRSQQ==",
            "7U9rzyAf+WZSfBPZ0mU89w==",
            "O1abzomrrD2JRr4JmgZnZg==",
            "hxn0uYLC5N1f/MbgYIW06w==",
        ]
        
        /// Magic data from 0x103dbbde0.
        private static let table: [UnsafePointer<Block>] = {
            let text = """
            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
            """
            // Read the contents of the dump file.
            guard let data = NSData(base64Encoded: text, options: .ignoreUnknownCharacters) else {
                return [] // Warning: The certificate is lost.
            }
            
            // Self-locking: When data is created never released.
            objc_setAssociatedObject(data, "self", data, .OBJC_ASSOCIATION_RETAIN)
            
            // Read segment data.
            let base = data.bytes.bindMemory(to: Block.self, capacity: 0)
            return stride(from: 0, to: 24, by: 1).map {
                return base.advanced(by: 256 * $0)
            }
        }()
    }
}
